<!DOCTYPE html>
<html>
	<head>
		<title>物联网，工厂3D可视化系统，显示标签，自动旋转</title>
		<script type="text/javascript" src="libs/three.js"></script>
		<script type="text/javascript" src="libs/OrbitControls.js"></script>
		<script type="text/javascript" src="libs/OBJLoader.js"></script>
		<script type="text/javascript" src="libs/CSS2DRenderer.js"></script>
		<style>
			body {
				margin: 0;
				overflow: hidden;
			}
			.laber_name {
				color: rgb(0, 255, 255);
				width: 100px;
				height: 30px;
				font-size: 14px;
				padding: 15px;
				background: url(assets/textures/msg-bg.png) no-repeat;
				background-size: cover;
			}
			.laber_name::after {
				content: "";
				width: calc(100% + 22px);
				height: 39px;
				background-position: 0 0;
				position: absolute;
				bottom: -40px;
				left: -22px;
				background: url(assets/textures/corner.png) no-repeat;
			}
		</style>
	</head>
	<body>
		<div id="dom"></div>
		<script type="text/javascript">
			var camera;
			var renderer;
			var labelRenderer;
			var cloud;
			var rainy_sw = 3; // 1雨2雪3晴4阴
			var flame_sw = true;
			//初始化一个空容器，装载粒子
			var krq = new THREE.Object3D();
			var textureLoader = new THREE.TextureLoader();
			var group3 = new THREE.Group();

			function init() {
				// 创建一个场景，它将包含我们所有的元素，如物体，相机和灯光。
				var scene = new THREE.Scene();

				var cubeLoader = new THREE.CubeTextureLoader();

				// 创建一个摄像机，它定义了我们正在看的地方
				camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 0.1, 20000);
				// 将摄像机对准场景的中心
				camera.position.x = 100;
				camera.position.y = 80;
				camera.position.z = -150;
				camera.lookAt(scene.position);
				var orbit = new THREE.OrbitControls(camera);
				orbit.autoRotate = true;
				setTimeout(function(){
					orbit.autoRotate = false;
				}, 7000)

				// 创建一个渲染器并设置大小，WebGLRenderer将会使用电脑显卡来渲染场景
				renderer = new THREE.WebGLRenderer({
					antialias: true,
					logarithmicDepthBuffer: true,
				});
				renderer.setClearColor(new THREE.Color("#0e0934"));
				renderer.setSize(window.innerWidth, window.innerHeight);
				var alight = new THREE.AmbientLight("#ffffff", 1);
				alight.name = "aLight";
				scene.add(alight);

				// 将平面添加到场景中
				createPlaneGeometryBasicMaterial();
				// 立方体
				createBoxGeometryBasicMaterial();
				creatRoadSurface();
				createRoundGeometryBasicMaterialMax();
				createRoundGeometryBasicMaterialMin();
				crateWall();
				
				labelRenderer = new THREE.CSS2DRenderer(); //新建CSS2DRenderer 
				labelRenderer.setSize(window.innerWidth, window.innerHeight);
				labelRenderer.domElement.style.position = 'absolute';
				labelRenderer.domElement.style.top = 0;
				document.body.appendChild(labelRenderer.domElement);

				// 将呈现器的输出添加到HTML元素
				document.getElementById("dom").appendChild(renderer.domElement);

				// 启动动画
				renderScene();

				// 创建圆仓大
				function createRoundGeometryBasicMaterialMax() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/textures/gong001.obj', function(obj) {
						var mesh = obj.children[0];
						mesh.material = new THREE.MeshBasicMaterial({
							map: new THREE.TextureLoader().load('assets/textures/d001.png'),
							transparent: true,
							side: THREE.DoubleSide,
							clipIntersection: true,
						});
						mesh.rotateZ(Math.PI);
						mesh.position.set(-40, 36, -105);

						for (let i = 0; i < 2; i++) {
							for (let j = 0; j < 3; j++) {
								var mc = mesh.clone();
								mc.translateX(i * 28);
								mc.translateZ(j * 20);
								scene.add(mc);
								
								let text = "大存储罐-G" + (i + 1) * (j + 1);
								let vector = new THREE.Vector3(-40 - (i * 28) , 50, -105 + (j * 20));
								let pointLabel = createLableObj(text, vector);
								scene.add(pointLabel);
							}
						}
					});
				}
				
				// 新建标签
				function createLableObj(text, vector) {
					let laberDiv = document.createElement('div');//创建div容器
					laberDiv.className = 'laber_name';
					laberDiv.textContent = text + '\n' + "余量：123";
					let pointLabel = new THREE.CSS2DObject(laberDiv);   
					pointLabel.position.set(vector.x, vector.y, vector.z);
					return pointLabel;
				}

				// 创建圆仓小
				function createRoundGeometryBasicMaterialMin() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/textures/002.obj', function(obj) {
						var mesh = obj.children[0];
						mesh.material = new THREE.MeshBasicMaterial({
							map: new THREE.TextureLoader().load('assets/textures/002.png'),
							transparent: true,
							side: THREE.DoubleSide,
							clipIntersection: true,
						});
						mesh.rotateZ(Math.PI);
						mesh.position.set(-40, 20, -19);

						for (let i = 0; i < 2; i++) {
							for (let j = 0; j < 6; j++) {
								var mc = mesh.clone();
								mc.translateX(i * 28);
								mc.translateZ(j * 24);
								scene.add(mc);
								
								let text = "小存储罐-G" + (i + 1) * (j + 1);
								let vector = new THREE.Vector3(-40 - (i * 28) , 35, -19 + (j * 24));
								let pointLabel = createLableObj(text, vector);
								scene.add(pointLabel);
							}
						}
					});
				}
				
				// 创建围栏
				function crateWall() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/textures/wall.obj', function(obj) {
						obj.scale.set(0.98, 0.6, 1);
						var texLan = new THREE.TextureLoader().load('assets/textures/lan2.png');
						// 纹理重复
						texLan.wrapS = THREE.RepeatWrapping;
						texLan.wrapT = THREE.RepeatWrapping;
						texLan.repeat.set(40, 1);
						obj.children[0].material = new THREE.MeshBasicMaterial({
							side: THREE.DoubleSide,
							map: texLan,
							transparent: true,
						});
						obj.children[1].material = new THREE.MeshBasicMaterial({
							map: new THREE.TextureLoader().load('assets/textures/door.png'),
							side: THREE.DoubleSide,
							transparent: true,
						});
						scene.add(obj)
					});
				}

				// 创建房屋
				function createBoxGeometryBasicMaterial() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/textures/003.obj', function(obj) {
						var mesh = obj.children[0];
						mesh.material = new THREE.MeshBasicMaterial({
							map: new THREE.TextureLoader().load('assets/textures/003.png'),
						});
						mesh.scale.set(1.3, 1.4, 1.5);
						mesh.position.set(11, 0, -85);

						for (let i = 0; i < 2; i++) {
							for (let j = 0; j < 3; j++) {
								var mc = mesh.clone();
								mc.translateX(i * 52);
								mc.translateZ(j * 83);
								scene.add(mc);
								
								let text = "工作厂房-W" + (i + 1) * (j + 1);
								let vector = new THREE.Vector3(11 + (i * 52) , 28, -85 + (j * 83));
								let pointLabel = createLableObj(text, vector);
								scene.add(pointLabel);
							}
						}
					});
				}

				/**
				 * 创建地面并添加材质
				 * wrapS属性定义的是纹理沿x轴方向的行为，而warpT属性定义的是纹理沿y轴方向的行为。
				 * Three.js为这些属性提供了如下两个选项：
				 * ·THREE.RepeatWrapping允许纹理重复自己。
				 * ·THREE.ClampToEdgeWrapping是属性的默认值。
				 * 属性值为THREE.ClampToEdgeWrapping时，那么纹理的整体不会重复，只会重复纹理边缘的像素来填满剩下的空间。
				 */
				function createPlaneGeometryBasicMaterial() {
					var cubeMaterial = new THREE.MeshStandardMaterial({
						map: textureLoader.load("assets/textures/floor3.png"),
						transparent: true,
						side: THREE.DoubleSide,
					});
					// 创建地平面并设置大小
					var planeGeometry = new THREE.PlaneGeometry(270, 260);
					var plane = new THREE.Mesh(planeGeometry, cubeMaterial);

					// 设置平面位置并旋转
					plane.rotation.x = -0.5 * Math.PI;
					plane.position.y = -0.1;
					scene.add(plane);
				}

				function creatRoadSurface() {
					var textureLoader = new THREE.TextureLoader();
					var geometry = new THREE.PlaneGeometry(24, 280);
					var texture = textureLoader.load('assets/textures/road2.png');
					texture.wrapS = THREE.RepeatWrapping;
					texture.wrapT = THREE.RepeatWrapping;
					texture.repeat.set(1, 10);
					var material = new THREE.MeshBasicMaterial({
						map: texture,
						side: THREE.DoubleSide,
					});
					var mesh = new THREE.Mesh(geometry, material);
					scene.add(mesh);
					mesh.rotateX(-Math.PI / 2);
					mesh.position.x = 105.5
				}

				function renderScene() {
					orbit.update(); // 拖动

					if (cloud) {
						var vertices = cloud.geometry.vertices;
						vertices.forEach(function(v) {
							v.y = v.y - (v.velocityY);
							v.x = v.x - (v.velocityX);

							if (v.y <= 0) v.y = 60;
							if (v.x <= -20 || v.x >= 20) v.velocityX = v.velocityX * -0.8;
						});
						cloud.geometry.verticesNeedUpdate = true;
					}

					// 使用requestAnimationFrame函数进行渲染
					requestAnimationFrame(renderScene);
					renderer.render(scene, camera);
					labelRenderer.render(scene, camera);
				}

				// 渲染的场景
				renderer.render(scene, camera);
				labelRenderer.render( scene, camera );
			}
			window.onload = init;

			// 随着窗体的变化修改场景
			function onResize() {
				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();
				renderer.setSize(window.innerWidth, window.innerHeight);
			}
			// 监听窗体调整大小事件
			window.addEventListener('resize', onResize, false);
		</script>
	</body>
</html>
